import {FieldType, FormlyFieldConfig} from '@ngx-formly/core';
import {ApiService} from '@core/services/http/api.service';
import {Events} from '@core/services/events/Events';
import {ExpressionService} from '@core/services/expression/ExpressionService';
import {Subject} from 'rxjs';
import {startWith, takeUntil, tap} from 'rxjs/operators';
import {deepCompare, exists, missing} from '../../../../utils/utils';
import {ElementRef, Renderer2} from '@angular/core';
import {SubjectService} from '@core/services/events/subject.service';

/**
 * 功能：表单字段基类
 */
export class ApesField extends FieldType {

  protected onDestroy$ = new Subject<any>();

  protected oldValues = {};

  protected listenFuncs: Function[] = [];

  constructor(protected apiService: ApiService, protected events: Events, protected expressionService: ExpressionService, protected subject: SubjectService) {
    super();
  }

  ngOnInit(): void {

  }


  ngOnDestroy(): void {
    this.onDestroy$.next();
    this.onDestroy$.complete();
    if (this.field && this.field.templateOptions.componentRef) {
      delete this.field.templateOptions.componentRef;
    }
    this.listenFuncs.forEach(listenFunc => {
      // Removes "listen" listener
      listenFunc();
    });
  }

  private _field: FormlyFieldConfig;

  set field(field) {
    this._field = field;
    this._field.templateOptions.componentRef = this;
  }

  get field() {
    return this._field;
  }

  /**
   * 功能：监听From变更
   * @param {string} fieldName 变更字段
   * @param {string} expression 执行的方法体
   */
  interceptFrom(fieldName: string, expression: string) {
    const ctrl = this.form.get(fieldName);
    if (ctrl == null) {
      console.error('字段：' + fieldName + ' 不存在，depends 失效！');
      return;
    }

    this.form.get(fieldName).valueChanges.pipe(
      takeUntil(this.onDestroy$),
      startWith(this.form.get(fieldName).value),
      tap(value => {
        /**非编辑状态**/
        if (this.formState.states !== 'submit' && this.field.type!="conditionInput") return;
        if (value === undefined) return;
        const oldValue = this.oldValues[fieldName];
        if (deepCompare(oldValue, value)) return;
        this.oldValues[fieldName] = value;
        this.evaluate(expression, {
          context: this.formState,
          form: this.form,
          field: this.field,
          model: this.formState.model,
          value: value,
          oldValue: oldValue,
          source: fieldName
        });
      }),
    ).subscribe();
  }

  /**
   * 功能：监听Table变更
   * @param {string} fieldName 变更字段
   * @param {string} expression 执行的方法体
   */
  interceptTable(tableName: string, fieldName: string, expression: string) {
    this.subject.subscribe(this.formState, tableName, params => {
      if (exists(params) && exists(params.colDef)) {
        const source = params.colDef.field;
        if (fieldName === source) {
          this.evaluate(expression, {
            context: this.formState,
            form: this.form,
            field: this.field,
            model: this.formState.model,
            data: params.data,
            value: params.value
          });
        }
      } else {
        /**表格数据删除**/
        this.evaluate(expression, {
          context: this.formState,
          form: this.form,
          field: this.field,
          model: this.formState.model,
          data: null,
          value: null
        });
      }
    });
  }

  protected evaluate(expression: string, params: any) {
    const result = this.expressionService.evaluate(expression, params, true);
    if (expression.indexOf('return') >= 0) {
      this.field.formControl.setValue(result);
    }
  }

  /**
   * 功能：动态添加事件
   * @param {ElementRef} elementRef
   * @param {Renderer2} renderer
   */
  protected addEventListener(elementRef: ElementRef, renderer: Renderer2) {
    if (missing(this.to.events)) return;
    // change  用户改变域的内容  *
    // click 鼠标点击某个对象  *
    // dblclick  鼠标双击某个对象  *
    // keydown 某个键盘的键被按下  *
    // keypress  某个键盘的键被按下或按住  *
    // keyup 某个键盘的键被松开  *
    // keyup.enter 回车事件  *
    // mousedown 某个鼠标按键被按下  *
    // mousemove 鼠标被移动  *
    // mouseout  鼠标从某元素移开  *
    // mouseover 鼠标被移到某元素之上  *
    // mouseup 某个鼠标按键被松开  *
    // select  文本被选定  *
    // submit  提交按钮被点击  *
    // reset  重置按钮被点击
    // resize  窗口或框架被调整尺寸
    // unload  用户退出页面
    // focus 元素获得焦点
    // blur  元素失去焦点
    // error 当加载文档或图像时发生某个错误
    // load  某个页面或图像被完成加载
    // abort 图像加载被中断
    this.to.events.forEach(em => {
      em.type.split(',').filter(type => type === 'change' || type === 'click'
        || type === 'dblclick' || type === 'keydown'
        || type === 'keypress' || type.split('.')[0] === 'keypress'
        || type === 'keyup' || type.split('.')[0] === 'keyup'
        || type === 'mousedown' || type === 'mousemove'
        || type === 'mouseout' || type === 'mouseover'
        || type === 'mouseup' || type === 'select'
        || type === 'submit' || type === 'reset'
        || type === 'resize' || type === 'unload'
        || em.type === 'focus' || type === 'blur'
        || type === 'error' || type === 'load'
        || type === 'abort')
        .forEach(type => {
          const listenFunc = renderer.listen(elementRef.nativeElement, type, (event) => {
            this.expressionService.evaluate(em.callback, {
              context: this.formState,
              form: this.form,
              field: this.field,
              model: this.formState.model,
              value: event.target.value
            }, true);
          });
          this.listenFuncs.push(listenFunc);
        });
    });
  }

  /**
   * 功能：注册事件监听器
   * @param {string} topic
   */
  interceptEventListener(topic: string) {
    const events = this.to.events;
    if (missing(events)) return;
    events.forEach(em => {
      em.type.split(',').filter(type => type === topic)
        .forEach(type => {
          /**订阅事件**/
          this.subject.subscribe(this.formState, topic, data => {
            // this.addListeners(this.subject.event_form_refresh);
            this.expressionService.evaluate(em.callback, {
              context: this.formState,
              form: this.form,
              field: this.field,
              model: this.formState.model
            }, true);
          });

        });
    });
  }

  // 添加默认提示
  // prefix 前缀
  protected addDefalutPlaceholder(prefix: string) {
    if (!this.to.placeholder && this.to.required) {
      this.to.placeholder = prefix + this.to.label;
    }
  }


}
